{***************************************************************
    SpyGestion  Copyright (C) 2008 Christophe KOALI <nature2gas@gmail.com>
    
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    
****************************************************************}
unit modParsingClassIStatistiques;

interface

uses modParsingClassBase,
     modBaseType,
     Classes,
     sFonctionsChaines,
     SysUtils,
     Windows,

     modStatsPlayers,

     LibXmlParser;



type

    TStatsType = (stoPoints, stoFlottes, stoRecherche);

    TParsingPlayerStats = class(IParsingRedirection)
    private
       FStatsList: TListStatsPlayerSP;

       FLinkSwitchPointsGeneral: string;
       FLinkSwitchPointsFlottes: string;
       FLinkSwitchPointsRecherche: string;
       FLinkSwichtPointsSelected: integer;

       // indice 1: Top 100  ; Indice 2: Top 200, etc...
       // contient les données à poster
       FLinkSwitchTop : array[1..15] of string;

       // format à utiliser
       FFormatToUse: string;


       FTypeStats : TStatsType;

       FDontAddToList: boolean;

       // <rank>
       //FDataToPost: string;

       // Indice de la page en cours
       FLinkSwitchTopSelected: integer;

       // Sert pour le parsing car on n'utilise pas les données de OnContent
       FLinkCurrPos: integer;



       FInSelect: integer;

       FInTable: boolean;
       FCurrTableLigne: integer;
       FCurrTableColonne: integer;

       FCanWaitForTable: boolean;
       FInForm : boolean;

       // Joueur en cours
       FCurrentPlayer: TPlayerStats;



    protected
       procedure InitPlayer;

    public
       property TypeStats : TStatsType read FTypeStats write FTypeStats;

       property Stats        : TListStatsPlayerSP read FStatsList;
       property DontAddToList: boolean            read FDontAddToList write FDontAddToList;

       function GetLinkTop(Index: integer): string;
       
       property LienSwitchPointsGeneral  : string  read FLinkSwitchPointsGeneral;
       property LienSwitchPointsFlottes  : string  read FLinkSwitchPointsFlottes;
       property LienSwitchPointsRecherche: string  read FLinkSwitchPointsRecherche;
       property LienSwitchPointsSelected : integer read FLinkSwichtPointsSelected;



       /////////////////////////////////////////////////////////////////////////
       // Implémentation de IParsingRedirection

        // initialise l'interface
        procedure Initialisation; override;

        // obtient le résultat d'analyse
        function  GetFinalState: TParsingResultState; override;

        procedure SetFullURLFromBase(const BaseLink: string); override;


        procedure ScanOnStartTag(Sender: TObject; TagName: string; Attributes: TAttrList); override;
        procedure ScanOnEndTag(Sender: TObject; TagName: string); override;
        procedure ScanOnContent(Sender: TObject; Content: string); override;

       //
       /////////////////////////////////////////////////////////////////////////


       constructor Create;
       destructor Destroy; override;
    end;


implementation

uses modLanguageParsing,
     sHTMLFonctions,
     ESBDates,
     modCore;


const
    CNT_STATSPLAYER_PGTYPE_GENERAL = 1;
    CNT_STATSPLAYER_PGTYPE_FLOTTES = 2;
    CNT_STATSPLAYER_PGTYPE_RECHERCHE = 3;


const
    CNT_SELECT_WITCHSTATS = 2;
    CNT_SELECT_TOP_LEVEL  = 3;

procedure TParsingPlayerStats.SetFullURLFromBase(const BaseLink: string);
var i: integer;
begin
    inherited;

// Note: ceci NE sont PLUS des liens mais les données à poster
//    for i := 1 to 15 do
//       FLinkSwitchTop[i] := sHTML_Get_URL_Lien(BaseLink, FLinkSwitchTop[i]);
end;



procedure TParsingPlayerStats.Initialisation;
var i: integer;

begin
    inherited;

    FLinkSwitchPointsGeneral   := '';
    FLinkSwitchPointsFlottes   := '';
    FLinkSwitchPointsRecherche := '';
    FLinkSwichtPointsSelected  := -1;

    // indice 1: Top 100  ; Indice 2: Top 200, etc...
    for i := 1 to 15 do
       FLinkSwitchTop[i] := ''; // : array[1..15] of string;

    // Indice de la page en cours
    FLinkSwitchTopSelected := -1;

    // Sert pour le parsing car on n'utilise pas les données de OnContent
    FLinkCurrPos:= 1;



    FInSelect  := -1;

    FInTable   := false;
    FCurrTableLigne   := 0;
    FCurrTableColonne := 0;

    FCanWaitForTable := false;

    InitPlayer;

    FFormatToUse := '';

    
    FStatsList.Clear;



end;

function TParsingPlayerStats.GetFinalState: TParsingResultState;
var i, k: integer;
    sType: string;
begin

    Result := PRESULT_ECHEC;

    sType := 'pts';
    
    case FTypeStats of
        stoPoints   : sType := 'pts';
        stoFlottes  : sType := 'flt';
        stoRecherche: sType := 'res';
    end;


    if FFormatToUse <> '' then begin
       if FFormatToUse[1] <> '&' then begin
          FFormatToUse := '&' + FFormatToUse;
       end;
    end;

    // A CAUSE DE LA MISE A JOUR, on définit nous même les données
    // à poster pour aller plus vite
    FFormatToUse := 'who=player&type=%s&start=%d' + FFormatToUse;
                     
    k := 1;
    for i := 1 to 15 do begin
       FLinkSwitchTop[i] := format(FFormatToUse, [sType, k]);
       Inc(k, 100);
    end;
    FError := false;



    for i := 1 to 15 do begin
       if FLinkSwitchTop[i] = '' then begin
          DoDebugContent('Erreur: Un lien est manquant -> numéro ' + IntToStr(i));
          FError := true;
          break;
       end;

    end;


    if FError then begin
       exit;
    end;

    Result := NoT(PRESULT_ECHEC);


end;


function TParsingPlayerStats.GetLinkTop(Index: integer): string;
begin

   Result := '';
   if Index < 1 then exit;
   if Index > 15 then exit;
   Result := FLinkSwitchTop[Index];
   
end;

procedure TParsingPlayerStats.ScanOnStartTag(Sender: TObject; TagName: string; Attributes: TAttrList);
label lTable;
var CurrBalise, sIsSelected, sTmp: string;
    xPos: integer;
begin

   TagName := lowercase(TagName);

   if TagName = 'form' then begin
      // La prochaine ouverture de balise table sera la bonne

      FInForm := true;
      exit;
   end;

   if FInForm = false then begin
      goto lTable;
   end;



   if TagName = 'select' then begin
      CurrBalise := Attributes.Value('name');

      // <select name="wer" size="1" onchange="haha(this)">
      // <select name="typ" size="1" onchange="haha(this)">
      // <select name=von size=1 onchange="haha(this)" >

      CurrBalise := lowercase(CurrBalise);

      FCanWaitForTable := true;

      if CurrBalise = 'typ' then
         FInSelect := CNT_SELECT_WITCHSTATS
      else if CurrBalise = 'von' then
         FInSelect := CNT_SELECT_TOP_LEVEL
      else
         FInSelect := -1;

   end else if TagName = 'option' then begin

      CurrBalise  := Attributes.Value('value');
      sIsSelected := Attributes.Value('selected');
      sIsSelected := trim(sIsSelected);

      if FInSelect = CNT_SELECT_WITCHSTATS then begin
//<option value="/game/stat.php?session=0000&von=0&typ=pkt" selected >Points
//<option value="/game/stat.php?session=0000&von=0&typ=flotten"  >Flottes
//<option value="/game/stat.php?session=0000&von=0&typ=forschung"  >Recherche

         sTmp := lowercase(Currbalise);

         if pos('pkt', sTmp) > 0 then begin
            FLinkSwitchPointsGeneral    := Currbalise;
            if sIsSelected = '1' then
               FLinkSwichtPointsSelected := CNT_STATSPLAYER_PGTYPE_GENERAL;

         end else if pos('flotten', sTmp) > 0 then begin
            FLinkSwitchPointsFlottes    := Currbalise;
            if sIsSelected = '1' then
               FLinkSwichtPointsSelected := CNT_STATSPLAYER_PGTYPE_FLOTTES;

         end else if pos('forschung', sTmp) > 0 then begin
            FLinkSwitchPointsRecherche  := Currbalise;
            if sIsSelected = '1' then
               FLinkSwichtPointsSelected := CNT_STATSPLAYER_PGTYPE_RECHERCHE;

         end else begin
            // Inconnu
            FError := true;
         end;

      end else if FInSelect = CNT_SELECT_TOP_LEVEL then begin
// <option value="/game/stat.php?session=0000&von=200" >201-300

          if FLinkCurrPos < 1 then begin
             // Impossible
             FError := true;
             exit;
          end;

          if FLinkCurrPos > 15 then begin
             // Indice hors limite
             FError := true;
             exit;
          end;

          FLinkSwitchTop[FLinkCurrPos] := Currbalise;

          if sIsSelected = '1' then
             FLinkSwitchTopSelected := FLinkCurrPos;

             
          Inc(FLinkCurrPos);
      end;
      
   end else if TagName = 'input' then begin
      CurrBalise  := lowercase(Attributes.Value('type'));

      if SameText(CurrBalise, 'hidden') then begin

         FFormatToUse := FFormatToUse + '&' + Attributes.Value('name') + '=' + Attributes.Value('value');
      end;

   end;



lTable:
   if FCanWaitForTable = false then exit;


   if TagName = 'table' then begin
      FInTable := true;

      FCurrTableLigne  := 0;
      FCurrTableColonne := 0;
   end;

   if FInTable = false then exit;


   if TagName = 'tr' then begin
      // Nouvelle ligne
      FCurrTableColonne := 0;
      Inc(FCurrTableLigne);


      // Réinitialise le joueur
      InitPlayer;


   end else if (TagName = 'td') or (TagName = 'th') then begin
      Inc(FCurrTableColonne);

   end;


   if (TagName = 'a') and (FCurrTableColonne = 3) then begin
      // Lien pour lui envoyer un message, et ainsi connaitre les
      // coordonnées de sa planète mère;
      // <a href="writemessages.php?session=00000&messageziel=11111">
      CurrBalise  := lowercase(Attributes.Value('href'));

      xPos := pos('messageziel=', CurrBalise);

      if xPos = 0 then begin
         // Ils ont changé la syntaxe
         FError := true;
      end else begin
         System.Delete(CurrBalise, 1, xPos + length('messageziel=') - 1);

         FCurrentPlayer.Uid := StrToIntDef(CurrBalise, -1);

         if FCurrentPlayer.Uid < 0 then
            FError := true;
            
      end;

   end;

end;

procedure TParsingPlayerStats.ScanOnEndTag(Sender: TObject; TagName: string);
begin

    TagName := lowercase(TagName);

    if TagName = 'select' then begin
       FInSelect := -1;

    end else if TagName = 'table' then begin
       FInTable := false;

    end else if TagName = 'tr' then begin

      if (FCurrentPlayer.Place > 0) and (FCurrentPlayer.Points >= 0) and (FCurrentPlayer.Nom <> '') then begin
         // On le sauvegarde
         if FDontAddToList = false then
            FStatsList.Ajout(FCurrentPlayer);
            
         FCurrentPlayer.Place := 0;

      end;

    end;

end;

procedure TParsingPlayerStats.ScanOnContent(Sender: TObject; Content: string);
var i: integer;
begin

    // Les données sont utiles seulement si on est dans le tableau
    if FInTable = false then exit;

    // La première ligne contient l'header du tableau
    if FCurrTableLigne <= 1 then exit;


    case FCurrTableColonne of
        1: begin
               // Place;
               try
                  i := pos('&', Content);
                  if i > 0 then begin
                     System.Delete(Content, i, maxint);
                  end;

                  Content := sfcRemplace(Content, '.', '');
                  
                  if FCurrentPlayer.Place < 0 then
                     FCurrentPlayer.Place := StrToInt(Content);
                     
               except
                  FCurrentPlayer.Place := -1;
               end;

           end;
        2: begin
               // Pseudo;
               FCurrentPlayer.Nom := trim(Content);
           end;

        3: begin
               // Lien pour lui envoyer un message, et ainsi connaitre les
               // coordonnées de sa planète mère;
               // On ignore
           end;
        4: begin
               // alliance;
               FCurrentPlayer.Alliance := Trim(Content);
           end;
        5: begin
               // Nombre de points;
               try
                  Content := sfcRemplace(Content, '.', '');
                  Content := sfcRemplace(Content, ',', '');
                  FCurrentPlayer.Points := StrToInt(Content);
               except
                  FCurrentPlayer.Points := -1;
               end;
           end;

        else begin


           end;
    end;



end;
    
procedure TParsingPlayerStats.InitPlayer;
begin
   FCurrentPlayer.Place    := -1;
   FCurrentPlayer.Points   := -1;
   FCurrentPlayer.Nom      := '';
   FCurrentPlayer.Alliance := '';
   FCurrentPlayer.Uid      := 0;
end;



constructor TParsingPlayerStats.Create;
begin
    inherited;

    FStatsList := TListStatsPlayerSP.Create;
    FDontAddToList := false;

    FTypeStats := stoPoints;
end;

destructor TParsingPlayerStats.Destroy; 
begin

    FStatsList.Free;
    
    inherited;
end;



end.
